<?php

namespace App\Library\Service;

use App\Library\Logic\AddressLogic;
use App\Library\Logic\CouponLogic;
use App\Library\Logic\CouponUserRelatedLogic;
use App\Library\Logic\LogisticsLogic;
use App\Library\Logic\OpenIdLogic;
use App\Library\Logic\OperateLogLogic;
use App\Library\Logic\PaymentRelatedLogic;
use App\Library\Logic\ShopOrderExtLogic;
use App\Library\Logic\ShopOrderLogic;
use App\Library\Logic\ProductSpecLogic;
use App\Library\Requests\Base\BasePageRequest;
use App\Library\Requests\Base\SerialNumberRequest;
use App\Library\Requests\ProductOrder\ProductOrderCheckRequest;
use App\Library\Requests\ProductOrder\ProductOrderCreateRequest;
use App\Library\Requests\ProductOrder\ProductOrderDeliveryRequest;
use App\Library\Requests\ProductOrder\ProductOrderPageRequest;
use App\Library\Requests\ProductOrder\ProductOrderPaymentRequest;
use App\Library\Requests\ProductOrder\ProductOrderSellerPageRequest;
use App\Library\Requests\ProductOrder\ProductOrderSellerRemarkRequest;
use App\Library\Requests\ProductOrder\ProductOrderUserPageRequest;
use App\Library\Service\Payment\WechatService;
use App\Library\YsdLib;
use App\Models\ShopUserModel;
use Exception;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Arr;
use Yansongda\Artful\Exception\ContainerException;
use Yansongda\Pay\Pay;

class ProductOrderService extends BaseService
{
    /**
     * @param ShopOrderLogic $logic
     */
    public function __construct(ShopOrderLogic $logic)
    {
        $this->logic = $logic;
    }

    /**
     * paging
     * @param ProductOrderPageRequest $request
     * @return JsonResponse
     */
    public function paging(ProductOrderPageRequest $request): JsonResponse
    {
        if (prod() && config('app.superId') !== MAINID) return fail();
        else return success($this->logic->paging($request));
    }

    /**
     * userPaging
     * @param ProductOrderUserPageRequest $request
     * @return JsonResponse
     */
    public function userPaging(ProductOrderUserPageRequest $request): JsonResponse
    {
        $data = $this->logic->userPaging($request);
        foreach ($data->items() as $v) {
            $v->plugTtl = $v->plug > 0 ? (int)__('base.plugCancelTtl') - 5 : 0;
        }
        return success(paginate($data));
    }

    /**
     * paging
     * @param ProductOrderSellerPageRequest $request
     * @return JsonResponse
     */
    public function sellerPaging(ProductOrderSellerPageRequest $request): JsonResponse
    {
        return success($this->logic->sellerPaging($request));
    }

    /**
     * userDetail
     * @param SerialNumberRequest $request
     * @return JsonResponse
     */
    public function userDetail(SerialNumberRequest $request): JsonResponse
    {
        $order = $this->logic->userDetail($request->serialNumber);
        if (is_null($order)) return fail(433);
        $order->order_total_real_price = bcsub($order->order_total_price, $order->order_ensure_price, 2);
        $order->ext;
        $order->goods;
        $order->packages;
        $order->return_logistics = is_null($order->orderReturn) ? null : $order->orderReturn->logistics;
        $order->plugTtl = $order->plug > 0 ? (int)__('base.plugCancelTtl') - 5 : 0;
        unsetObject($order, 'order_id');
        return success($order);
    }

    /**
     * sellerDetail
     * @param SerialNumberRequest $request
     * @return JsonResponse
     */
    public function sellerDetail(SerialNumberRequest $request): JsonResponse
    {
        $order = $this->logic->sellerDetail($request->serialNumber);
        if (is_null($order)) return fail(433);
        $order->ext;
        $order->goods;
        $order->packages;
        $order->return_logistics = is_null($order->orderReturn) ? null : $order->orderReturn->logistics;
        unsetObject($order, 'order_id');
        return success($order);
    }

    /**
     * check
     * @param ProductOrderCheckRequest $request
     * @return JsonResponse
     */
    public function check(ProductOrderCheckRequest $request): JsonResponse
    {
        return success(ProductSpecLogic::checkByIds($request->array));
    }

    /**
     * create
     * @param ProductOrderCreateRequest $request
     * @return JsonResponse
     * @throws ContainerException
     * @throws GuzzleException|Exception
     */
    public function create(ProductOrderCreateRequest $request): JsonResponse
    {
        if ($request->isCart === true) return fail(422);
        else {
            $address = AddressLogic::detail($request->addressId);
            if (is_null($address) || $address->user_id !== USERID) return fail(422);
        }
        $specList = ProductSpecLogic::getByIds(array_keys($request->specArr));
        if ($specList->count() !== count($request->specArr)) return failMessage('商品状态发生变化');
        $data = ShopOrderLogic::getCreateData($specList, $request);
        if (is_string($data)) return failMessage($data);
        else if (!is_null($request->couponNumber)) {
            if ($data['agent']) return fail(422);
            $couponUserRelated = CouponUserRelatedLogic::findBySerialNumber($request->couponNumber);
            if (is_null($couponUserRelated)) return failMessage('优惠券不存在');
            else if ($couponUserRelated->status === 1) return failMessage('优惠券已使用');
            else if (is_null($couponUserRelated->coupon)) return failMessage('优惠券不存在');
            else if (!is_null($couponUserRelated->coupon->start_at) && now()->lte(now()->parse($couponUserRelated->coupon->start_at))) {
                return failMessage('优惠券未到使用时间');
            } else if (!is_null($couponUserRelated->coupon->end_at) && now()->gte(now()->parse($couponUserRelated->coupon->start_at))) {
                return failMessage('优惠券已经过期');
            } else if ($couponUserRelated->coupon->full_amount > 0 && $couponUserRelated->coupon->full_amount > $data['price']) {
                return failMessage('优惠券未到满减金额');
            }
            $couponUserRelated->status = 1;
            $couponUserRelated->save();
            $couponUserRelated->coupon->use_count++;
            $couponUserRelated->coupon->save();
        }
        $order = $this->logic->add($request, $data, $address, $couponUserRelated ?? null);
        $paymentRelated = PaymentRelatedLogic::addByProductOrder($order);
        Pay::config(YsdLib::config());
        $order->title = '异宠星球';
        return WechatService::mini($order, $paymentRelated->serial_number, $request->code);
    }

    /**
     * cancel
     * @param SerialNumberRequest $request
     * @return JsonResponse
     */
    public function cancel(SerialNumberRequest $request): JsonResponse
    {
        $order = $this->logic->findBySerialNumber($request);
        if (is_null($order) || $order->buy_user_id !== USERID || $order->order_is_delete === 1) fail(433);
        else if (!is_null($order->ext->cancel_at)) return failMessage('订单已经取消');
        else if ($order->order_status === 1) return failMessage('订单已经支付');
        $this->logic->cancel($request->serialNumber);
        return success();
    }

    /**
     * payment
     * @param ProductOrderPaymentRequest $request
     * @return JsonResponse
     * @throws ContainerException
     * @throws GuzzleException
     */
    public function payment(ProductOrderPaymentRequest $request): JsonResponse
    {
        $order = $this->logic->userDetail($request->serialNumber, ['order_status', 'order_buy_status', 'pay_price']);
        if (is_null($order)) return fail(433);
        else if ($order->order_status === 1) return failMessage('订单已经支付');
        else if ($order->order_buy_status === 3) return failMessage('订单已经取消');
        else if ($order->status === 0) return failMessage('订单已经取消');
        $paymentRelated = PaymentRelatedLogic::addByProductOrder($order);
        Pay::config(YsdLib::config());
        $order->title = '异宠星球';
        return WechatService::mini($order, $paymentRelated->serial_number, $request->code);
    }

    /**
     * userDelete
     * @param SerialNumberRequest $request
     * @return JsonResponse
     */
    public function userDelete(SerialNumberRequest $request): JsonResponse
    {
        $order = $this->logic->userDetail($request->serialNumber);
        if (is_null($order)) return fail(433);
        else if (!in_array($order->ext->status, [0, 4, 5])) return failMessage('只能删除已取消和已完成的订单');
        $order->order_is_delete = 1;
        $order->save();
        $order->ext->user_deleted_at = now();
        $order->ext->save();
        return success();
    }

    /**
     * confirm
     * @param SerialNumberRequest $request
     * @return JsonResponse
     * @throws Exception
     */
    public function confirm(SerialNumberRequest $request): JsonResponse
    {
        $order = $this->logic->findBySerialNumber($request->serialNumber);
        if (is_null($order)) return fail(433);
        else if ($order->ext->status !== 3) return failMessage('订单状态不正确');
        $order->order_buy_status = 5;
        $order->order_sell_status = 5;
        $order->order_confirm_time = time();
        $order->save();
        $order->ext->status = 4;
        $order->ext->status_confirm = 1;
        $order->ext->confirm_at = now();
        $order->ext->save();
        ProductSpecLogic::decStockByConfirm($order);
        mq('shopOrderSettlement', $order->serial_number, (int)__('base.settleTtl'));
        return success();
    }

    /**
     * 订单统计
     * @return JsonResponse
     *
     */
    public function tj(): JsonResponse
    {
        if (USERID === MAINID || POWER === 1) $userId = MAINID;
        else $userId = USERID;

        $data['user_order'] = $this->logic->userOrderTj();
        $data['seller_order'] = $this->logic->userOrderTj(1, $userId);
        return success($data);
    }

    /**
     * ext统计
     * @return JsonResponse
     */
    public function extTj(): JsonResponse
    {
        return success(ShopOrderExtLogic::tj());
    }

    /**
     *
     * @param ProductOrderDeliveryRequest $request
     * @return JsonResponse
     * @throws Exception|GuzzleException
     */
    public function delivery(ProductOrderDeliveryRequest $request): JsonResponse
    {
        $model = $this->logic->findByWhere(['serialNumber' => $request->serialNumber]);
        if (is_null($model)) return fail(433);
        else if ($model->ext->status_pay === 0) return fail(614);
        else if ($model->order_is_self_pickup === 1) return fail(629);
        else if ($model->ext->status_cancel) return fail(631);
        else if (in_array($model->ext->status_after_sale, [1, 2])) return fail(632);

        //从字符串中提取快递单号
        $expressesNo = array_unique(array_filter(explode(',', $request->expressesNo), function ($v) {
            return $v !== '';
        }));

        //数据组装
        $arr = [];
        foreach ($expressesNo as $v) {
            LogisticsService::delivery($model->order_id, $v);
        }

        //更新订单状态
        /* if ($model->ext->status === 2) {
             $model->ext->status = 3;
             $model->ext->status_deliver = 1;
             $model->ext->deliver_at = now()->toDateTimeString();
             $model->ext->save();
         }*/
        ShopOrderExtLogic::query()->where([
            'status' => 2,
            'order_id' => $model->order_id
        ])->update([
            'status' => 3,
            'status_deliver' => 1,
            'deliver_at' => now()->toDateTimeString()
        ]);

        //插入
        LogisticsLogic::insert($arr);
        mq('shopOrderConfirm', $model->serial_number, (int)__('base.confirmTtl'));
        OperateLogLogic::add();
        return success();
    }

    /**
     * 查看物流信息
     * @param SerialNumberRequest $request
     * @return JsonResponse
     *
     */
    public function logistics(SerialNumberRequest $request): JsonResponse
    {
        $model = $this->logic->findByWhere(['serialNumber' => $request->serialNumber]);
        if (is_null($model)) return fail(433);
        else if ($model->order_is_self_pickup === 1) return fail(645);
        else if ($model->ext->status_deliver !== 1) return fail(615);
        else if ($model->ext->status_cancel === 1) return fail(434);
        return success($model->oneLogistics);
    }

    /**
     *
     * @param SerialNumberRequest $request
     * @return JsonResponse
     *
     */
    public function selfPickup(SerialNumberRequest $request): JsonResponse
    {
        $model = $this->logic->findBySerialNumber($request);
        if (is_null($model)) return fail(433);
        else if (!$model->ext->status_pay) return fail(614);
        else if ($model->ext->status_cancel) return fail(631);
        else if ($model->ext->status_after_sale) return fail(632);
        else if ($model->ext->status_deliver) return fail(643);

        $model->order_is_self_pickup = 1;
        $model->save();
        $model->ext->status = 3;
        $model->ext->deliver_at = now()->toDateTimeString();
        $model->ext->status_deliver = 1;
        $model->ext->status_pickup = 1;
        $model->ext->save();
        return success();
    }

    public function sellerRemark(ProductOrderSellerRemarkRequest $request): JsonResponse
    {
        $model = $this->logic->findBySerialNumber($request);
        if (is_null($model)) return fail(433);
        $model->ext->seller_remark = htmlspecialchars(strip_tags(trim($request->remark)));
        $model->ext->save();
        OperateLogLogic::add();
        return success();
    }

    public function customerServicePaging(BasePageRequest $request): JsonResponse
    {
        return success($this->logic->customerServicePaging($request));
    }

    public function plugAnnounce(BasePageRequest $request): JsonResponse
    {
        $data = $this->logic->plugAnnounce($request);
        foreach ($data->items() as $v) {
            if ($v->user_id === config('app.plugId')) {
                if (!is_null($v->extend)) $v->mobile = Arr::get(json_decode($v->extend, true), 'plug.mobile');
            }
            $v->mobile = substr_replace($v->mobile, '****', 3, 4);
            $v->file_id = $v->spec_file_id ?? $v->product_file_id;
            unsetObject($v, ['user_id', 'extend', 'product_file_id', 'spec_file_id']);
        }
        return success(paginate($data));
    }
}
